package main

import (
	"context"
	"fmt"
	"time"

	jsoniter "github.com/json-iterator/go"
	"github.com/tendermint/tendermint/abci/example/kvstore"
	"github.com/tendermint/tendermint/my_test/config"
	"github.com/tendermint/tendermint/my_test/performance/entity"
	"github.com/tendermint/tendermint/rpc/client/http"

	"encoding/json"
)

var cli *http.HTTP

func init() {
	var err error
	cli, err = http.New(config.DefaultIPAndPort, "/websocket")
	if err != nil {
		panic(err)
	}
}

func searchByHeight(heightList []int64, objectId string, cumulativeHash []byte) {
	var (
		provRes = new(entity.ProvResult)
	)

	for i := len(heightList) - 1; i >= 0; i-- {
		if i+1 < len(heightList) && heightList[i] == heightList[i+1] {
			continue
		}

		h := heightList[i]

		blockRes, err := cli.Block(context.TODO(), &h)
		if err != nil {
			panic(err)
		}

		for index := len(blockRes.Block.Txs) - 1; index >= 0; index-- {
			var tx kvstore.Tx

			if err = json.Unmarshal(blockRes.Block.Txs[index], &tx); err != nil {
				panic(err)
			}

			if tx.Data.ObjectID == objectId {
				fmt.Println("objectId =", objectId, "height =", h, "index =", index)
				// fmt.Printf("%+v\n\n", tx)

				tx.Data = nil

				provRes.Txs = append(provRes.Txs, &tx)

				if config.EnableMerkleProofVerification {
					proof := blockRes.Block.Txs.Proof(index)
					if err = proof.Validate(blockRes.Block.DataHash); err != nil {
						panic(err)
					}
					provRes.MerkleProofList = append(provRes.MerkleProofList, &entity.MerkleProof{
						TxProof:  proof,
						RootHash: blockRes.Block.DataHash,
					})
				}
			}
		}
	}

	// provRes.MerkleProofList = nil

	jsonProvRes, err := jsoniter.Marshal(provRes)
	if err != nil {
		panic(err)
	}

	fmt.Println(string(jsonProvRes))
}

func single(ctx context.Context, targetObjectId string) {
	var (
		heightList     []int64
		cumulativeHash []byte
	)

	begin := time.Now()
	defer func() {
		fmt.Println(float64(time.Since(begin).Milliseconds())/float64(config.Loop), "ms")
	}()

	for l := 0; l < config.Loop; l++ {
		abciQueryRes, err := cli.ABCIQuery(ctx, "", nil)
		if err != nil {
			panic(err)
		}

		blockRes, err := cli.Block(ctx, &abciQueryRes.Response.Height)
		if err != nil {
			panic(err)
		}

		mptQueryRes, err := cli.MPTQuery(ctx, blockRes.Block.Header.MPTHash, targetObjectId)
		if err != nil {
			panic(err)
		}

		if mptQueryRes != nil {
			heightList = mptQueryRes.HeightList
			cumulativeHash = mptQueryRes.CumulativeHash
		}

		searchByHeight(heightList, targetObjectId, cumulativeHash)
	}
}

func main() {
	single(context.TODO(), "108497")
}
